#ifndef XGE_XTHREAD_H_
#define XGE_XTHREAD_H_
#include "xge_common_config.h"
#include "xstring.h"
#include "xsmart_ptr.h"
#include "xbase_common.h"
#include <Windows.h>

//$Revision: 2011/12/23
//1.Delete the function "Kill" since it is implemented by using TerminateThread on Win32
//such calling can easily lead to deadlock and other buggy code.
//I have happened to have such bugs , if you place the CRT code like printf inside of a thread
//when the MainThread call Kill , and than call printf , it is very possible to lead to the
//dead-lock , since the termination of any thread which is using CRT function will lead to
//the CRT internal lock not calling unlock routine , when you call corresponding CRT function
//again it will lead to the dead lock.Our sub-class which take advantage of Thread class will
//implement its own mechanism to exit the thread.
//$

namespace xge{
namespace xge_internal{

  class ThreadManager;
  // A win32 thread implementation
  // since we gonna use CRT stuff
  // so we create the thread by using _beginthreadex instead of ::CreateThread
  // the difference is that the latter one will lead to tiny memory leak by calling
  // CRT in that thread .
  class ThreadHandler : public Allocator {
  private: 
    // CTor
    ThreadHandler( const String& name , ::HANDLE handler );
    ~ThreadHandler();
    friend struct DefaultDestructor<ThreadHandler>;
  public:

    // Get an unique thread id of this thread
    // if this thread is running 
    size_t GetUniqueThreadID();
    // Join this thread
    // wait until the thread expired
    // After the join the handler of this thread
    // is invalid again which means it has been set
    // to INVALID_HANDLE_VALUE
    // so you can restart this thread by calling Spawn again
    const TripleResult Join();
    const TripleResult Join( int ms );

    // Test if this thread is running or not
    const TripleResult IsRunning() const;

    const String& name() const {
      return name_;
    }

    // set the name of this XThread
    // it won't hurt even if this XThread is
    // not spawn yet
    void set_name( const String& name ) {
      name_ = name;
    }

    // Is invalid will determine this thread is not a valid running thread
    // not about running or not running
    bool IsValid() const {
      return thread_handler_ != INVALID_HANDLE_VALUE;
    }

    // Suspend the xthread .
    // Using it wisely , since it is not the way to do the
    // synchronization , using specific synchronization class 
    // to do , using this function only when debug or some
    // special stage .

    // the calling_count if specified , will store the value of the last suspend-count of this thread
    // LAST CALL
    // so if the *calling_count == 0 , means the thread just suspend 
    bool SuspendXThread(
      size_t* calling_count
      );

    // Every calling of SuspendXThread should also call ResumeXThread once
    // What is more , if you use XThread::Spawn( false ) 
    // The thread will be created however , will not be able to run right away
    // You should call ResumeXThread( xthread ) to run the thread really
    // the calling_count if specified , will store the value of the last suspend-count of this thread
    // LAST CALL
    // so if the *calling_count == 1 , means the thread just resume to run
    bool ResumeXThread(
      size_t* calling_count
      );

  private:
    // Clear is not terminate the thread
    // it just release the kernel handler  
    void Clear();
    void SetDebugName( const char * name );
  private:
    friend class ThreadManager;
    ::HANDLE thread_handler_;
    String name_;
    // Also no copy 
    DISALLOW_COPY_AND_ASSIGN(ThreadHandler);
  }; 

  typedef SharedPtr< ThreadHandler , DefaultDestructor<ThreadHandler> > ThreadHandlerPtr ;


} // namespace xge_internal
}// namespace xge

#endif//